﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Data;
using System.Data.Objects.DataClasses;
using IRC.IRepairClouds.DataLayer.Cache;
using System.Linq.Expressions;
using System.Reflection;


namespace IRC.IRepairClouds.DataLayer
{
    public static partial class EntityCached
    {
        private const string EntitySetNamePrefix = "ICloudRepairEntities.";

        private static T CreateCached<T, TKey>(ICloudRepairEntities dbContext, Expression<Func<ICloudRepairEntities, ObjectQuery<T>>> setSelector, Expression<Func<T, TKey>> keySelector, TKey keyValue) where T : EntityObject
        {
            setSelector.ThrowIfNull("setSelector");
            keySelector.ThrowIfNull("keySelector");

            var me = setSelector.Body as MemberExpression;
            if(me == null)
                throw new ArgumentOutOfRangeException("setSelector", "Is not MemberExpression");
            if (me.Member.MemberType != MemberTypes.Property)
                throw new ArgumentOutOfRangeException("setSelector", "Is not Property");
            if (!(me.Expression is ParameterExpression))
                throw new ArgumentOutOfRangeException("setSelector", "Is not Property");
            var entitySetName = me.Member.Name;

            me = keySelector.Body as MemberExpression;
            if (me == null)
                throw new ArgumentOutOfRangeException("keySelector", "Is not MemberExpression");
            if (me.Member.MemberType != MemberTypes.Property)
                throw new ArgumentOutOfRangeException("keySelector", "Is not Property");
            if (!(me.Expression is ParameterExpression))
                throw new ArgumentOutOfRangeException("keySelector", "Is not Property");
            var keyName = me.Member.Name;

            EntityKey key = new EntityKey(EntitySetNamePrefix + entitySetName, keyName, keyValue);
            return CreateCached<T>(dbContext, key);
        }

        //private static T CreateCached<T>(ICloudRepairEntities dbContext, string entitySetName, string keyName, object keyValue) where T : EntityObject
        //{
        //    EntityKey key = new EntityKey(EntitySetNamePrefix + entitySetName, keyName, keyValue);
        //    return CreateCached<T>(dbContext, key);
        //}

        //private static T CreateCached<T>(ICloudRepairEntities dbContext, string entitySetName, IEnumerable<EntityKeyMember> entityKeyValues) where T : EntityObject
        //{
        //    EntityKey key = new EntityKey(EntitySetNamePrefix + entitySetName, entityKeyValues);
        //    return CreateCached<T>(dbContext, key);
        //}

        private static T CreateCached<T>(ICloudRepairEntities dbContext, EntityKey entityKey) where T : EntityObject
        {
            T entity = null;
            ObjectStateEntry entry;
            if (dbContext.ObjectStateManager.TryGetObjectStateEntry(entityKey, out entry))
                entity = (T)entry.Entity;
            if (entity == null) {
                entity = CacheManager.Entities.Get<T>(dbContext, entityKey);
                if (entity != null) {
                    try {
                        dbContext.Attach(entity);
                    }
                    catch (InvalidOperationException ex) {
                        ex.Data["entryBefore"] = entry.JSON_BaseSerializeEx();
                        try {
                            entity = null;
                            if (dbContext.ObjectStateManager.TryGetObjectStateEntry(entityKey, out entry)) {
                                ex.Data["entryAfterExists"] = "true";
                                entity = (T)entry.Entity;
                            }
                            ex.Data["entryAfter"] = entry.JSON_BaseSerializeEx();
                            ex.Data["entityAfter"] = entity.JSON_BaseSerializeEx();
                        }
                        catch (Exception) { }
                        ex.Data["entityKey"] = entityKey.JSON_BaseSerializeEx();
                        //ExceptionHandling.Log(ex, Webix.Diagnostics.Logging.LogSeverity.Warning);
                    }
                }
            }
            return entity;
        }
    }
}
